// Services/TrafficMonitorService.cs

using System.Diagnostics;
using System.Net.NetworkInformation;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
using Microsoft.AspNetCore.SignalR;
using Microsoft.EntityFrameworkCore;
using NetworkFlowMonitor.Scripts.Data;
using SharpPcap;
using SharpPcap.LibPcap;
using PacketDotNet;

namespace NetworkFlowMonitor.Scripts.Service;

public class TrafficMonitorService : BackgroundService
{
    private readonly ILogger<TrafficMonitorService> _logger;
    private readonly IServiceProvider _serviceProvider;
    private readonly Timer _deviceDiscoveryTimer;
    private readonly Dictionary<string, TrafficUpdate> _trafficUpdates;
    private readonly Dictionary<string, DeviceStats> _deviceStats = new();
    
    // 存储连接信息
    private readonly Dictionary<string, DeviceConnection> _connections = new();

    // 存储上次采集的流量数据，用于计算速率
    private readonly
        Dictionary<string, (long received, long sent, long downloadRate, long uploadRate, DateTime timestamp)>
        _previousStats = new();

    private List<LibPcapLiveDevice> _monitoredDevices = new();

    public static TrafficMonitorService Instance;

    public TrafficMonitorService(
        ILogger<TrafficMonitorService> logger,
        IServiceProvider serviceProvider)
    {
        _logger = logger;
        _serviceProvider = serviceProvider;
        _deviceDiscoveryTimer = new Timer(DiscoverDevices, null, Timeout.Infinite, Timeout.Infinite);
        _trafficUpdates = new();
        _monitoredDevices = new List<LibPcapLiveDevice>();
        Instance = this;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        _logger.LogInformation("流量监控服务已启动");

        // 初始延迟后开始监控
        await Task.Delay(5000, stoppingToken);

        // 每30秒扫描一次设备
        _deviceDiscoveryTimer.Change(0, 2000);

        // 开始使用SharpPcap监控流量
        StartPcapMonitoring();

        while (!stoppingToken.IsCancellationRequested)
        {
            await Task.Delay(1000, stoppingToken);
        }
    }

    private void StartPcapMonitoring()
    {
        try
        {
            var devices = LibPcapLiveDeviceList.Instance;
            _logger.LogInformation($"找到 {devices.Count} 个网络设备");

            if (devices.Count == 0)
            {
                _logger.LogWarning("未找到网络设备");
                return;
            }

            // 记录所有设备信息用于诊断
            foreach (var device in devices)
            {
                try
                {
                    if (device.Interface == null || device.Interface.FriendlyName == null ||
                        !device.Interface.FriendlyName.Equals("eth1", StringComparison.OrdinalIgnoreCase))
                    {
                        continue;
                    }

                    _logger.LogInformation(
                        $"设备信息 - Name: {device.Name}, FriendlyName: {device.Interface.FriendlyName}, Description: {device.Interface.Description}, Opened: {device.Opened}, LinkType: {device.LinkType}");
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, $"获取设备 {device.Name} 信息时出错");
                }
            }

            // 选择eth1网络接口进行监控
            foreach (var device in devices)
            {
                try
                {
                    if (device.Interface == null || device.Interface.FriendlyName == null ||
                        !device.Interface.FriendlyName.Equals("eth1", StringComparison.OrdinalIgnoreCase))
                    {
                        continue;
                    }

                    _logger.LogInformation(
                        $"检查设备: {device.Interface.FriendlyName}, 描述: {device.Interface.Description}");


                    _logger.LogInformation($"尝试打开设备: {device.Interface.FriendlyName}");

                    // 确保设备正确打开
                    if (!device.Opened)
                    {
                        // 尝试不同的打开方式
                        try
                        {
                            _logger.LogInformation($"以混杂模式打开设备: {device.Interface.FriendlyName}");
                            device.Open(DeviceModes.Promiscuous, 1000);
                            _logger.LogInformation($"成功以混杂模式打开设备: {device.Interface.FriendlyName}");
                        }
                        catch (PcapException ex)
                        {
                            _logger.LogError(ex, $"以混杂模式打开设备 {device.Interface.FriendlyName} 失败，尝试普通模式");
                            try
                            {
                                device.Open();
                                _logger.LogInformation($"以普通模式成功打开设备: {device.Interface.FriendlyName}");
                            }
                            catch (Exception innerEx)
                            {
                                _logger.LogError(innerEx, $"以普通模式打开设备 {device.Interface.FriendlyName} 也失败了");
                                throw;
                            }
                        }
                        catch (Exception ex)
                        {
                            _logger.LogError(ex, $"打开设备 {device.Interface.FriendlyName} 时发生未知错误");
                            throw;
                        }
                    }
                    else
                    {
                        _logger.LogInformation($"设备 {device.Interface.FriendlyName} 已经处于打开状态");
                    }

                    // 检查设备是否已正确打开
                    if (device.Opened)
                    {
                        _logger.LogInformation($"设备 {device.Interface.FriendlyName} 状态: Opened={device.Opened}");

                        try
                        {
                            var linkType = device.LinkType;
                            _logger.LogInformation($"设备 {device.Interface.FriendlyName} LinkType: {linkType}");
                        }
                        catch (Exception ex)
                        {
                            _logger.LogError(ex, $"获取设备 {device.Interface.FriendlyName} LinkType时出错");
                        }

                        device.OnPacketArrival += DeviceOnPacketArrival;
                        device.Filter = "ether proto \\arp or ip"; // 监控ARP和IP流量
                        device.StartCapture();
                        _monitoredDevices.Add(device);
                        _logger.LogInformation($"开始监控设备: {device.Interface.FriendlyName}");
                    }
                    else
                    {
                        _logger.LogError($"设备 {device.Interface.FriendlyName} 未能正确打开");
                    }
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, $"无法打开设备 {device.Interface.FriendlyName}");
                }
            }

            _logger.LogInformation($"总共监控 {_monitoredDevices.Count} 个设备");
            foreach (var device in _monitoredDevices)
            {
                _logger.LogInformation($"正在监控的设备: {device.Interface.FriendlyName}");
            }
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "启动PCAP监控时发生错误");
        }
    }

    private void DeviceOnPacketArrival(object sender, PacketCapture e)
    {
        try
        {
            var rawPacket = e.GetPacket();
            var packet = Packet.ParsePacket(rawPacket.LinkLayerType, rawPacket.Data);

            var ethernetPacket = packet.Extract<EthernetPacket>();
            if (ethernetPacket == null) return;

            var sourceMac = ethernetPacket.SourceHardwareAddress.ToString();
            var destMac = ethernetPacket.DestinationHardwareAddress.ToString();

            // 更新发送方统计数据
            UpdateDeviceStats(sourceMac, ethernetPacket.Bytes.Length, 0);

            // 更新接收方统计数据
            UpdateDeviceStats(destMac, 0, ethernetPacket.Bytes.Length);
            
            // 处理IP数据包以跟踪连接
            ProcessIpPacket(packet, ethernetPacket);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "处理数据包时发生错误");
        }
    }
    
    // 处理IP数据包以跟踪连接
    private void ProcessIpPacket(Packet packet, EthernetPacket ethernetPacket)
    {
        try
        {
            var ipPacket = packet.Extract<IPPacket>();
            if (ipPacket == null) return;
            
            // 创建连接标识符（源IP:端口->目标IP:端口）
            string connectionId = "";
            string reverseConnectionId = "";
            
            if (ipPacket.Protocol == PacketDotNet.ProtocolType.Tcp)
            {
                var tcpPacket = packet.Extract<TcpPacket>();
                if (tcpPacket != null)
                {
                    connectionId = $"{ipPacket.SourceAddress}:{tcpPacket.SourcePort}->{ipPacket.DestinationAddress}:{tcpPacket.DestinationPort}";
                    reverseConnectionId = $"{ipPacket.DestinationAddress}:{tcpPacket.DestinationPort}->{ipPacket.SourceAddress}:{tcpPacket.SourcePort}";
                }
            }
            else if (ipPacket.Protocol == PacketDotNet.ProtocolType.Udp)
            {
                var udpPacket = packet.Extract<UdpPacket>();
                if (udpPacket != null)
                {
                    connectionId = $"{ipPacket.SourceAddress}:{udpPacket.SourcePort}->{ipPacket.DestinationAddress}:{udpPacket.DestinationPort}";
                    reverseConnectionId = $"{ipPacket.DestinationAddress}:{udpPacket.DestinationPort}->{ipPacket.SourceAddress}:{udpPacket.SourcePort}";
                }
            }
            else
            {
                // 其他IP协议
                connectionId = $"{ipPacket.SourceAddress}->${ipPacket.DestinationAddress}";
                reverseConnectionId = $"{ipPacket.DestinationAddress}->${ipPacket.SourceAddress}";
            }
            
            // 更新或创建连接信息
            if (!_connections.ContainsKey(connectionId) && !_connections.ContainsKey(reverseConnectionId))
            {
                // 新连接
                var connection = new DeviceConnection
                {
                    ConnectionId = connectionId,
                    SourceIp = ipPacket.SourceAddress.ToString(),
                    DestinationIp = ipPacket.DestinationAddress.ToString(),
                    Protocol = ipPacket.Protocol.ToString(),
                    FirstSeen = DateTime.UtcNow,
                    LastSeen = DateTime.UtcNow,
                    BytesTransferred = ethernetPacket.Bytes.Length
                };
                
                _connections[connectionId] = connection;
            }
            else
            {
                // 更新现有连接
                var existingId = _connections.ContainsKey(connectionId) ? connectionId : reverseConnectionId;
                var connection = _connections[existingId];
                connection.LastSeen = DateTime.UtcNow;
                connection.BytesTransferred += ethernetPacket.Bytes.Length;
                
                // 如果是TCP连接，检查连接状态
                if (ipPacket.Protocol == PacketDotNet.ProtocolType.Tcp)
                {
                    var tcpPacket = packet.Extract<TcpPacket>();
                    if (tcpPacket != null)
                    {
                        if (tcpPacket.Finished || tcpPacket.Reset)
                        {
                            connection.IsClosed = true;
                        }
                    }
                }
            }
            
            // 清理过期连接（超过5分钟无活动）
            CleanupExpiredConnections();
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "处理IP数据包时发生错误");
        }
    }
    
    // 清理过期连接
    private void CleanupExpiredConnections()
    {
        var cutoffTime = DateTime.UtcNow.AddMinutes(-5);
        var expiredConnections = _connections
            .Where(kvp => kvp.Value.LastSeen < cutoffTime)
            .Select(kvp => kvp.Key)
            .ToList();
            
        foreach (var connectionId in expiredConnections)
        {
            _connections.Remove(connectionId);
        }
    }
    
    // 获取指定设备的连接信息
    public List<DeviceConnection> GetDeviceConnections(string deviceIp)
    {
        return _connections.Values
            .Where(c => c.SourceIp == deviceIp || c.DestinationIp == deviceIp)
            .ToList();
    }

    private void UpdateDeviceStats(string macAddress, long bytesSent, long bytesReceived)
    {
        if (!_deviceStats.TryGetValue(macAddress, out var stats))
        {
            stats = _deviceStats[macAddress] = new DeviceStats();
        }

        // Console.WriteLine($"更新设备 {macAddress} 的统计数据: 发送 {bytesSent} 字节，接收 {bytesReceived} 字节");

        stats.TotalBytesSent += bytesSent;
        stats.TotalBytesReceived += bytesReceived;
        stats.LastUpdate = DateTime.UtcNow;
    }

    private async void DiscoverDevices(object? state)
    {
        try
        {
            var arpTable = ReadArpTable();
            using var scope = _serviceProvider.CreateScope();
            var context = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
            var hubContext = scope.ServiceProvider.GetRequiredService<IHubContext<TrafficHub>>();

            foreach (var (mac, ip) in arpTable)
            {
                var device = await context.Devices
                    .FirstOrDefaultAsync(d => d.MacAddress == mac);

                // 获取设备的流量统计
                long totalReceived = 0;
                long totalSent = 0;
                long downloadRate = 0;
                long uploadRate = 0;

                var key = mac.Replace(":", string.Empty).ToUpper();
                if (_deviceStats.TryGetValue(key, out var stats))
                {
                    totalReceived = stats.TotalBytesReceived;
                    totalSent = stats.TotalBytesSent;

                    // 计算速率
                    if (_previousStats.TryGetValue(mac, out var previous))
                    {
                        var timeDiff = (DateTime.UtcNow - previous.timestamp).TotalSeconds;
                        if (timeDiff > 0)
                        {
                            downloadRate = (long)((totalReceived - previous.received) / timeDiff);
                            uploadRate = (long)((totalSent - previous.sent) / timeDiff);

                            downloadRate = (downloadRate + previous.downloadRate) / 2;
                            uploadRate = (uploadRate + previous.uploadRate) / 2;
                        }
                    }

                    // 更新上次统计
                    _previousStats[mac] = (totalReceived, totalSent, downloadRate, uploadRate, DateTime.UtcNow);
                }

                if (device == null)
                {
                    device = new Device
                    {
                        MacAddress = mac,
                        IpAddress = ip,
                        DeviceName = $"未知设备_{mac.Replace(":", "").Substring(0, 6)}",
                        FirstSeen = DateTime.UtcNow,
                        LastSeen = DateTime.UtcNow
                    };
                    context.Devices.Add(device);
                    await context.SaveChangesAsync();
                }
                else
                {
                    device.LastSeen = DateTime.UtcNow;
                    device.IpAddress = ip;
                    await context.SaveChangesAsync();
                }

                // 保存流量记录
                var trafficRecord = new TrafficRecord
                {
                    DeviceId = device.Id,
                    BytesReceived = totalReceived,
                    BytesSent = totalSent,
                    Timestamp = DateTime.UtcNow
                };

                context.TrafficRecords.Add(trafficRecord);
                await context.SaveChangesAsync();

                // 发送实时更新
                var update = new TrafficUpdate
                {
                    DeviceName = device.DeviceName ?? "未知设备",
                    IpAddress = ip,
                    MacAddress = mac,
                    DownloadSpeed = Math.Max(0, downloadRate),
                    UploadSpeed = Math.Max(0, uploadRate),
                    TotalDownload = totalReceived,
                    TotalUpload = totalSent,
                    Timestamp = DateTime.UtcNow
                };

                _trafficUpdates[update.MacAddress] = update;
            }

            // 通过 SignalR 发送实时更新
            if (_trafficUpdates.Any())
            {
                await hubContext.Clients.All.SendAsync("ReceiveTrafficUpdate", _trafficUpdates.Values);
            }

            // 清理不活跃的设备统计信息
            CleanupInactiveDevices();
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "发现设备时发生错误");
        }
    }

    public List<TrafficUpdate> GetLatestTraffic()
    {
        return _trafficUpdates.Values.ToList();
    }

    private void CleanupInactiveDevices()
    {
        var cutoffTime = DateTime.UtcNow.AddMinutes(-5); // 5分钟内无活动的设备
        var inactiveDevices = _deviceStats.Where(kvp => kvp.Value.LastUpdate < cutoffTime)
            .Select(kvp => kvp.Key)
            .ToList();

        foreach (var mac in inactiveDevices)
        {
            _deviceStats.Remove(mac);
            _previousStats.Remove(mac);
        }
    }

    private Dictionary<string, string> ReadArpTable()
    {
        var arpTable = new Dictionary<string, string>();

        try
        {
            // 检查操作系统
            if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
            {
                // 在Linux/Ubuntu上读取ARP表
                ReadArpTableLinux(arpTable);
            }
            else
            {
                // 在Windows上使用arp命令获取ARP表
                ReadArpTableWindows(arpTable);
            }
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "读取ARP表失败");
        }

        return arpTable;
    }

    private void ReadArpTableLinux(Dictionary<string, string> arpTable)
    {
        try
        {
            // Ubuntu上读取ARP表的标准方法
            var lines = File.ReadAllLines("/proc/net/arp");

            foreach (var line in lines.Skip(1)) // 跳过标题行
            {
                var parts = line.Split(new[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
                if (parts.Length >= 6)
                {
                    var ip = parts[0];
                    var mac = parts[3].ToLower();

                    if (mac != "00:00:00:00:00:00" && mac != "ff:ff:ff:ff:ff:ff")
                    {
                        arpTable[mac] = ip;
                    }
                }
            }
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "在Linux上读取ARP表失败");
        }
    }

    private void ReadArpTableWindows(Dictionary<string, string> arpTable)
    {
        try
        {
            var process = new Process
            {
                StartInfo = new ProcessStartInfo
                {
                    FileName = "arp",
                    Arguments = "-a",
                    RedirectStandardOutput = true,
                    UseShellExecute = false,
                    CreateNoWindow = true
                }
            };

            process.Start();
            var output = process.StandardOutput.ReadToEnd();
            process.WaitForExit();

            // 解析ARP表输出
            var lines = output.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
            foreach (var line in lines)
            {
                // 匹配类似这样的行: "192.168.1.1 00-11-22-33-44-55 动态"
                var match = System.Text.RegularExpressions.Regex.Match(line,
                    @"(\d+\.\d+\.\d+\.\d+)\s+([0-9a-fA-F\-]+)");
                if (match.Success)
                {
                    var ip = match.Groups[1].Value;
                    var mac = match.Groups[2].Value.Replace("-", ":").ToLower();
                    if (mac != "00:00:00:00:00:00" && mac != "ff:ff:ff:ff:ff:ff")
                    {
                        arpTable[mac] = ip;
                    }
                }
            }
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "在Windows上读取ARP表失败");
        }
    }

    private async Task<string> GetDeviceNameFromDns(string ip)
    {
        try
        {
            var process = new Process
            {
                StartInfo = new ProcessStartInfo
                {
                    FileName = "nslookup",
                    Arguments = ip,
                    RedirectStandardOutput = true,
                    UseShellExecute = false,
                    CreateNoWindow = true
                }
            };

            process.Start();
            var output = await process.StandardOutput.ReadToEndAsync();
            process.WaitForExit();

            var match = Regex.Match(output, @"name = ([^\r\n]+)");
            if (match.Success)
            {
                return match.Groups[1].Value.TrimEnd('.');
            }
        }
        catch
        {
            // 忽略DNS查询错误
        }

        return null;
    }

    public override async Task StopAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("流量监控服务正在停止");
        _deviceDiscoveryTimer?.Change(Timeout.Infinite, Timeout.Infinite);

        // 停止所有PCAP设备捕获
        foreach (var device in _monitoredDevices)
        {
            if (device.Opened)
            {
                try
                {
                    _logger.LogInformation($"停止捕获设备: {device.Interface.FriendlyName}");
                    device.StopCapture();
                    device.Close();
                    _logger.LogInformation($"已停止并关闭设备: {device.Interface.FriendlyName}");
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, $"停止设备 {device.Interface.FriendlyName} 时出错");
                }
            }
            else
            {
                _logger.LogInformation($"设备 {device.Interface.FriendlyName} 未打开，无需关闭");
            }
        }

        await base.StopAsync(cancellationToken);
    }
}

// 设备流量统计类
public class DeviceStats
{
    public long TotalBytesSent { get; set; }
    public long TotalBytesReceived { get; set; }
    public DateTime LastUpdate { get; set; } = DateTime.UtcNow;
}

// 连接信息类
public class DeviceConnection
{
    public string ConnectionId { get; set; }
    public string SourceIp { get; set; }
    public string DestinationIp { get; set; }
    public string Protocol { get; set; }
    public DateTime FirstSeen { get; set; }
    public DateTime LastSeen { get; set; }
    public long BytesTransferred { get; set; }
    public bool IsClosed { get; set; } = false;
}